﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace SDFL.Core
{
    public static class ByteExtensionMethods
    {
        /// <summary>
        /// Convert a byte to a Hex string representation, e.g. 255 to "FF"
        /// equal to 
        ///     BitConverter.ToString(new byte[]{255}); // "FF"
        /// </summary>
        /// <param name="b">byte</param>
        /// <returns>a string represent the Hex</returns>
        public static string ToHex(this byte b)
        {           
            return b.ToString("X2");
        }

        /// <summary>
        /// Convert a byte[] to a Hex[] string representation
        /// </summary>
        /// <param name="bytes">byte []</param>
        /// <returns>the string representation of Hex[]</returns>
        public static string ToHex(this IEnumerable<byte> bytes)
        {
            StringBuilder sb = new StringBuilder();  
            
            foreach (byte b in bytes)  
                sb.Append(b.ToString("X2")); 

            return sb.ToString(); 
        } 

        /// <summary>
        /// To Base64String
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string ToBase64String(byte[] bytes)  
        {  
            return Convert.ToBase64String(bytes); 
        }
                
        public static int ToInt(this byte[] value, int startIndex)  
        {  
            return BitConverter.ToInt32(value, startIndex);
        }  

        #region Bit operation
     
        /// <summary>
        /// check weather byte[index] is 1
        /// </summary>
        /// <param name="b"></param>
        /// <param name="index">from 0 to 7</param>
        /// <returns></returns>
        public static bool IsBitEqualOne(this byte b, int index)  
        {  
            return (b & (1 << index)) > 0;
        }

        /// <summary>
        /// set byte[index] to be 1 
        /// </summary>
        /// <param name="b"></param>
        /// <param name="index">from 0 to 7</param>
        /// <returns></returns>
        public static byte SetBitToOne(this byte b, int index)  
        {  
            b |= (byte)(1 << index);  
            return b;  
        }

        /// <summary>
        /// Set Bit to be Zero
        /// </summary>
        /// <param name="b"></param>
        /// <param name="index">from 0 to 7</param>
        /// <returns></returns>
        public static byte ClearBit(this byte b, int index)
        {
            b &= (byte)((1 << 8) - 1 - (1 << index));
            return b;
        }

        /// <summary>
        /// Reverse bit
        /// </summary>
        /// <param name="b"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        public static byte ReverseBit(this byte b, int index)  
        {  
            b ^= (byte)(1 << index);  
            return b; 
        }

        #endregion

        /// <summary>
        /// 使用指定算法Hash 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="hashName"></param>
        /// <returns></returns> 
        public static byte[] Hash(this byte[] data, string hashName)  
        {  
            HashAlgorithm algorithm; 

            if (string.IsNullOrEmpty(hashName))
                algorithm = HashAlgorithm.Create();  
            else algorithm = HashAlgorithm.Create(hashName);  
            
            return algorithm.ComputeHash(data);  
        }  
        
        /// <summary>
        /// 使用默认算法Hash
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>  
        public static byte[] Hash(this byte[] data) 
        {  
            return Hash(data, null); 
        } 
    }

    public static class StringExtensionMethods
    {
        /// <summary>
        /// Conver a Hex string to bytes[]
        /// </summary>
        /// <param name="HexString"></param>
        /// <returns></returns>
        public static byte[] ToByteArray(this string HexString)
        {
            int NumberChars = HexString.Length;
            byte[] bytes = new byte[NumberChars / 2];
            for (int i = 0; i < NumberChars; i += 2)
            {
                bytes[i / 2] = Convert.ToByte(HexString.Substring(i, 2), 16);
            }
            return bytes;
        }
    }
}
